"""处理异常 Core 模块"""
from typing import Any, Dict, Optional

from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from starlette.templating import _TemplateResponse

from slowapi.errors import RateLimitExceeded


class AlertException(HTTPException):
# “脚本警告窗口输出的异常类
# -从HTTPExceptiond接收用于页面移动的附加url参数。
# """

    def __init__(self, detail: str = None, status_code: int = 200, url: str = None):
        self.status_code = status_code
        self.detail = detail
        self.url = url


class AlertCloseException(HTTPException):
    """脚本警告窗口输出和窗口关闭的异常类"""

    def __init__(
        self,
        detail: Any = None,
        status_code: int = 200,
        headers: Optional[Dict[str, str]] = None,
    ) -> None:
        super().__init__(status_code=status_code, detail=detail, headers=headers)


class JSONException(Exception):
    """HTTPException的 'detail' 而不是一个关键 'message'用作键的异常类"""
    def __init__(self, status_code: int, message: str, **kwargs):
        self.status_code = status_code
        self.message = message
        self.kwargs = kwargs


# 不使用模板时异常处理处理程序的注册
class TemplateDisabledException(HTTPException):
    """模板不可用异常类"""

    def __init__(
        self,
        detail: Any = None,
        status_code: int = 200,
        headers: Optional[Dict[str, str]] = None,
    ) -> None:
        super().__init__(status_code=status_code, detail=detail, headers=headers)
        self.status_code = status_code
        self.detail = detail


class RedirectException(HTTPException):
    """具体 url由 redirect的异常类"""
    def __init__(self, status_code: int, url: str):
        self.status_code = status_code
        self.url = url


def regist_core_exception_handler(app: FastAPI) -> None:
    """在应用程序实例中注册异常处理程序."""

    @app.exception_handler(AlertException)
    async def alert_exception_handler(
            request: Request, exc: AlertException):
        """AlertException 处理异常 handler 注册"""
        context = {
            "request": request,
            "errors": exc.detail,
            "url": exc.url
        }
        return template_response("alert.html", context, exc.status_code)

    @app.exception_handler(AlertCloseException)
    async def alert_close_exception_handler(
            request: Request, exc: AlertCloseException):
        """AlertCloseException 处理异常 handler 注册"""
        context = {
            "request": request,
            "errors": exc.detail
        }
        return template_response("alert_close.html", context, exc.status_code)

    @app.exception_handler(TemplateDisabledException)
    async def template_disabled_exception_handler(
            request: Request, exc: TemplateDisabledException):
        """无法使用模板处理异常 handler 注册"""
        context = {
            "request": request,
            "errors": exc.detail
        }
        return template_response("503.html", context, exc.status_code)

    @app.exception_handler(JSONException)
    async def json_exception_handler(request: Request, exc: JSONException):
        """JSONException 处理异常 handler 注册"""
        content = {"message": exc.message}
        content.update(exc.kwargs)

        return JSONResponse(
            status_code=exc.status_code,
            content=content
        )

    @app.exception_handler(RedirectException)
    async def redirect_exception_handler(request: Request, exc: RedirectException):
        """RedirectException 处理异常 handler 注册"""
        return RedirectResponse(url=exc.url, status_code=exc.status_code)

    @app.exception_handler(RateLimitExceeded)
    async def rate_limit_exception_handler(request: Request, exc: RateLimitExceeded):
        """RateLimitExceeded 处理异常 handler 注册"""
        return JSONResponse(
            status_code=exc.status_code,
            content={"message": exc.detail}
        )


def template_response(
        template_html: str,
        context: Dict[str, Any],
        status_code: int = 200) -> _TemplateResponse:
    """返回一个模板响应对象.

    Args:
        template_html (_type_): 模板文件名
        context (_type_): context 对象
        status_code (int, optional): HTTP 状态代码. Defaults to 200.

    Returns:
        _TemplateResponse: 模板响应对象
    """
    from core.template import TemplateService, theme_asset

    # 创建新的模板响应对象.
    # - UserTemplates, AdminTemplates 设置默认上下文时，类 DB向上看,
    #   在第一次安装时， DB没有，所以创建一个新的模板响应对象.
    template = Jinja2Templates(directory=TemplateService.get_templates_dir())
    template.env.globals["theme_asset"] = theme_asset
    return template.TemplateResponse(
        name=template_html,
        context=context,
        status_code=status_code
    )
